package com.zlf.sb.demo.design.chain;

import org.springframework.beans.BeansException;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 每个处理器的通用行为
 * @param <T>
 */
@Component
public final class MerchantAdminChainContext<T> implements ApplicationContextAware, CommandLineRunner {
    /**
     * 应用上下文，通过Spring IOC获取Bean实例
     */
    private ApplicationContext applicationContext;

    /**
     * 保存商品上架责任链实现类
     * <p>
     * Key：{@link MerchantAdminAbstractChainHandler#mark()}
     * Val：{@link MerchantAdminAbstractChainHandler} 一组责任链实现 Spring Bean 集合
     * <p>
     * 比如有一个商品上架模板创建责任链，实例如下：
     * Key：MERCHANT_ADMIN_CREATE_PRODUCT_TEMPLATE_KEY
     * Val：
     * - 验证商品信息基本参数是否必填 —— 执行器  {@link ProductInfoNotNullChainFilter}
     * - 验证商品库存 —— 执行器 {@link ProductInventoryCheckChainFilter}
     */
    private final Map<String, List<MerchantAdminAbstractChainHandler>> abstractChainHandlerContainer = new HashMap<>();

    /**W22346879$a
     * eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbS9nb29nbGUuaWRlbnRpdHkuaWRlbnRpdHl0b29sa2l0LnYxLklkZW50aXR5VG9vbGtpdCIsImlhdCI6MTczODQyNTUwMywiZXhwIjoxNzM4NDI5MTAzLCJpc3MiOiJmaXJlYmFzZS1hZG1pbnNkay02cjM0eUB0YWJuaW5lLWF1dGgtMzQwMDE1LmlhbS5nc2VydmljZWFjY291bnQuY29tIiwic3ViIjoiZmlyZWJhc2UtYWRtaW5zZGstNnIzNHlAdGFibmluZS1hdXRoLTM0MDAxNS5pYW0uZ3NlcnZpY2VhY2NvdW50LmNvbSIsInVpZCI6Ik9sbWVyUVp2RHpmbDRvMXpWSEdFOGtuSFFLNDIifQ.QSxHk5_mFs2CljeqTSzvfQvWojCPSVh-pgJU83FSWgzwegV_L3FGJm1XVsj4CCqvHUdh8hA5gbcmlbXMn3AiDh5xB569NmEpLcpv-dXIhFj2_tSTMqcSNEkCAsn6133hmWY7FAdDoYL3er4Dbwh05wOQgGR1qC3RZsxs579ZFoUa7qxG_pSpiZPHL_9sbKgWZAZVoEmR7r1I9ROGdKd3vp_sVk-KDDjMQo7fsvsEB94nZElI0RWYvrMV4yXREGUmmY3Mk7wViw91zN6v0wg-72N4-7SXfeOJvNQ27T-MWxP1JmqC5nyIEgx2j-tHgs2g1pFqrmspwtHE7AXbrs3ZWw
     * 责任链组件执行
     * @param mark 责任链组件标识
     * @param requestObj 请求参数
     */
    public void handler(String mark,T requestObj){
        // 根据 mark 标识从责任链容器中获取一组责任链实现 Bean 集合
        List<MerchantAdminAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.get(mark);
        if (CollectionUtils.isEmpty(abstractChainHandlers)) {
            throw new RuntimeException(String.format("[%s] Chain of Responsibility ID is undefined.", mark));
        }
        abstractChainHandlers.forEach(each -> each.handler(requestObj));
    }

    /**
     * 执行方法，接收可变参数
     * 本方法主要用于初始化和处理商品上架抽象责任链容器
     * 它从Spring容器中获取所有MerchantAdminAbstractChainHandler类型的Bean，
     * 并根据它们的mark进行分类和排序，以便后续处理
     *
     * @param args 可变参数，可能包含方法运行所需的额外信息
     * @throws Exception 如果方法执行过程中遇到错误，抛出异常
     */
    @Override
    public void run(String... args) throws Exception {
        // 从 Spring IOC 容器中获取指定接口 Spring Bean 集合
        Map<String, MerchantAdminAbstractChainHandler> chainFilterMap = applicationContext.getBeansOfType(MerchantAdminAbstractChainHandler.class);
        // 遍历所有获取到的Bean，并将它们根据mark分类存入抽象责任链容器中
        chainFilterMap.forEach((beanName, bean) -> {
            // 判断 Mark 是否已经存在抽象责任链容器中，如果已经存在直接向集合新增；如果不存在，创建 Mark 和对应的集合
            List<MerchantAdminAbstractChainHandler> abstractChainHandlers = abstractChainHandlerContainer.getOrDefault(bean.mark(), new ArrayList<>());
            abstractChainHandlers.add(bean);
            abstractChainHandlerContainer.put(bean.mark(), abstractChainHandlers);
        });
        // 遍历抽象责任链容器，对每个 Mark 对应的责任链实现类集合进行排序
        abstractChainHandlerContainer.forEach((mark, chainHandlers) -> {
            // 对每个 Mark 对应的责任链实现类集合进行排序，优先级小的在前
            chainHandlers.sort(Comparator.comparing(Ordered::getOrder));
        });
        System.out.println("chainFilterMap = " + chainFilterMap);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public static void main(String[] args) {

    }
}